#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <malloc.h>
#include <unistd.h>

#include "common.h"
#include "sha1.h"
#include "upgrade.h"

//#include "ofprint_common.h"

#if 0
struct usb_id boot_id_table[] = {
    { .idVendor = THM36_BOOT_USB_VID, .idProduct = THM36_BOOT_USB_PID, .description = "THM36"},
    { .idVendor = CCM4201S_BOOT_USB_VID, .idProduct = CCM4201S_BOOT_USB_PID, .description = "CCM4201S"},
    { 0, 0, NULL},
};  
#endif

UPGRADE_PARAM upgrade_param;

//char new_firmware_name[FILE_PATH_LEN_MAX+FW_FILE_NAME_LEN_MAX] = {0};//固件文件路径
//char new_firmware_version[256] = {0};
//uint32 new_firmware_version_num = 0;


int32 upgrade_check_boot_mcu_type(void)
{
    UPGRADE_PARAM *this = &upgrade_param;
    
    if(0 == intf_usb_check_device_exist(&(this->acm32.usb_id)))
    {
        this->fw_boot_mcu_type = DEVICE_ACM32;
        return 0;
    }
    else if(0 == intf_usb_check_device_exist(&(this->thm36.usb_id)))
    {
        this->fw_boot_mcu_type = DEVICE_THM36;
        return 0;
    }
    else if(0 == intf_usb_check_device_exist(&(this->ccm4201s.usb_id)))
    {
        this->fw_boot_mcu_type = DEVICE_CCM4201S;
        return 0;
    }

    return -1;
}


static int32 upgrade_set_file_type(uint8 type)
{
    UPGRADE_PARAM *this = &upgrade_param;

    this->fw_file_mcu_type |= type;
    
    return 0;
}

uint8 upgrade_get_fw_file_mcu_type(void)
{
    UPGRADE_PARAM *this = &upgrade_param;

    return this->fw_file_mcu_type;
}

static uint8 upgrade_get_boot_mcu_type(void)
{
    UPGRADE_PARAM *this = &upgrade_param;

    return this->fw_boot_mcu_type;
}

FIRMWARE_VERSION_INFO *thm36_fw_upgrade_info(void)
{
    return &(upgrade_param.thm36_fw);
}

FIRMWARE_VERSION_INFO *ccm4201_fw_upgrade_info(void)
{
    return &(upgrade_param.ccm4201s_fw);
}

FIRMWARE_VERSION_INFO *acm32_fw_upgrade_info(void)
{
    return &(upgrade_param.acm32_fw);
}



int check_fw_file_version(char *file_name)
{
    UPGRADE_PARAM *this = &upgrade_param;
    int ret = -1;
    char fw_file_path[FILE_PATH_LEN_MAX+FW_FILE_NAME_LEN_MAX] = {0};
    char fw_version_str[FW_VERSION_LEN_MAX] = {0};
    int fw_version_num = 0;
    char *start = NULL;
    char *tail = NULL;
    
    if((NULL == file_name)||(0 >= strlen(file_name))||(FILE_PATH_LEN_MAX+FW_FILE_NAME_LEN_MAX < strlen(file_name)))
    {
        WD_ERR("固件文件名称错误!\n");
        goto END;
    }

    if('/' == file_name[0])//绝对路径,20231127
    {
        snprintf(fw_file_path, FILE_PATH_LEN_MAX+FW_FILE_NAME_LEN_MAX, "%s", file_name);
    }
    else//相对路径,20231127
    {
        char current_path[FILE_PATH_LEN_MAX] = {0};
        if(NULL == getcwd(current_path, FILE_PATH_LEN_MAX))
            WD_ERR("exec failed!\n");
        
        if(0 >= strlen(current_path))
        {
            WD_ERR("get firmware_path: FAIL!!!\n");
            goto END;
        }

        snprintf(fw_file_path, FILE_PATH_LEN_MAX+FW_FILE_NAME_LEN_MAX, "%s/%s", current_path, file_name);
        D_DBG("fw_file_path = %s\n", fw_file_path); 
    }
    
    tail = strstr(fw_file_path, FW_FILE_TAIL);
    if(NULL == tail)
    {
        goto END;
    }

    start = strstr(fw_file_path, THM36FP_V);
    if((NULL != start) && (tail > start) \
        && (FW_FILE_NAME_LEN_MAX >= (tail-start+strlen(FW_FILE_TAIL)))\
        && (FW_VERSION_NUM_LEN_MAX >= tail-start-strlen(THM36FP_V)))
    {
        char str_fmt[FW_FILE_NAME_LEN_MAX+FW_VERSION_LEN_MAX];

        memset(str_fmt, 0x00, FW_FILE_NAME_LEN_MAX+FW_VERSION_LEN_MAX);
        strcpy(str_fmt, THM36FP_V);
        strcat(str_fmt, "%d");
        strcat(str_fmt, FW_FILE_TAIL);
        
        sscanf(start, str_fmt, &fw_version_num);
        D_DBG("fw_version_num = %d\n", fw_version_num);
        if((fw_version_num <= 0)||(fw_version_num > 999999))
        {
            WD_ERR("固件文件名称错误!\n");
            goto END;
        }

        memset(str_fmt, 0x00, FW_FILE_NAME_LEN_MAX+FW_VERSION_LEN_MAX);
        strcpy(str_fmt, THM36_FW_VERSION_HEAD);
        strcat(str_fmt, "%06d");        

        snprintf(fw_version_str, FW_VERSION_LEN_MAX, str_fmt, fw_version_num);
        D_DBG("fw_version_str = %s\n", fw_version_str);

        strcpy(this->thm36_fw.file_path, fw_file_path);
        strcpy(this->thm36_fw.fw_version, fw_version_str);
        this->thm36_fw.fw_version_num = fw_version_num;
        D_DBG("fw_file_path = %s\n", this->thm36_fw.file_path);
        upgrade_set_file_type(DEVICE_THM36);
        ret = 0;
        goto END;
    }

    start = strstr(fw_file_path, CCM4201S_FW_V);
    if((NULL != start) && (tail > start) \
        && (FW_FILE_NAME_LEN_MAX >= (tail-start+strlen(FW_FILE_TAIL)))\
        && (FW_VERSION_NUM_LEN_MAX >= tail-start-strlen(CCM4201S_FW_V)))

    {
        char str_fmt[FW_FILE_NAME_LEN_MAX+FW_VERSION_LEN_MAX];
        
        memset(str_fmt, 0x00, FW_FILE_NAME_LEN_MAX+FW_VERSION_LEN_MAX);
        strcpy(str_fmt, CCM4201S_FW_V);
        strcat(str_fmt, "%d");
        strcat(str_fmt, FW_FILE_TAIL);

        sscanf(start, str_fmt, &fw_version_num);
        D_DBG("fw_version_num = %d\n", fw_version_num);
        if((fw_version_num <= 0)||(fw_version_num > 999999))
        {
            WD_ERR("固件文件名称错误!\n");
            goto END;
        }

        memset(str_fmt, 0x00, FW_FILE_NAME_LEN_MAX+FW_VERSION_LEN_MAX);
        strcpy(str_fmt, CCM4201S_FW_VERSION_HEAD);
        strcat(str_fmt, "%06d");        

        snprintf(fw_version_str, FW_VERSION_LEN_MAX, str_fmt, fw_version_num);
        D_DBG("fw_version_str = %s\n", fw_version_str);

        strcpy(this->ccm4201s_fw.file_path, fw_file_path);
        strcpy(this->ccm4201s_fw.fw_version, fw_version_str);
        this->ccm4201s_fw.fw_version_num = fw_version_num;

        upgrade_set_file_type(DEVICE_CCM4201S);
        ret = 0;
        goto END;
    }

    start = strstr(fw_file_path, ACM32FP_V);
    if((NULL != start) && (tail > start) \
        && (FW_FILE_NAME_LEN_MAX >= (tail-start+strlen(FW_FILE_TAIL)))\
        && (FW_VERSION_NUM_LEN_MAX >= tail-start-strlen(ACM32FP_V)))

    {
        char str_fmt[FW_FILE_NAME_LEN_MAX+FW_VERSION_LEN_MAX];
        
        memset(str_fmt, 0x00, FW_FILE_NAME_LEN_MAX+FW_VERSION_LEN_MAX);
        strcpy(str_fmt, ACM32FP_V);
        strcat(str_fmt, "%d");
        strcat(str_fmt, FW_FILE_TAIL);

        sscanf(start, str_fmt, &fw_version_num);
        D_DBG("fw_version_num = %d\n", fw_version_num);
        if((fw_version_num <= 0)||(fw_version_num > 999999))
        {
            WD_ERR("固件文件名称错误!\n");
            goto END;
        }

        memset(str_fmt, 0x00, FW_FILE_NAME_LEN_MAX+FW_VERSION_LEN_MAX);
        strcpy(str_fmt, ACM32_FW_VERSION_HEAD);
        strcat(str_fmt, "%06d");        

        snprintf(fw_version_str, FW_VERSION_LEN_MAX, str_fmt, fw_version_num);
        D_DBG("fw_version_str = %s\n", fw_version_str);

        strcpy(this->acm32_fw.file_path, fw_file_path);
        strcpy(this->acm32_fw.fw_version, fw_version_str);
        this->acm32_fw.fw_version_num = fw_version_num;

        upgrade_set_file_type(DEVICE_ACM32);
        ret = 0;
        goto END;
    }

END:
    return ret;
}


int read_fw_version(void)
{
    FILE *file;
    int file_size = 0;
    int read_size = 0;
    //int fw_version = 0;
    char firmware_name[FW_CONF_FILE_SIZE_MAX] = {0};
    UPGRADE_PARAM *this = &upgrade_param;

    file = fopen(FW_VERSION_FILE, "r");
    if(NULL == file)
    {
        D_DBG("%s open failed!\n", FW_VERSION_FILE);
        return -1;      
    }

    file_size = com_get_file_size(FW_VERSION_FILE);
    if((0 == file_size) || (FW_CONF_FILE_SIZE_MAX < file_size))//此处最大文件大小待确认
    {
        WD_ERR("%s file_size = %d, error!\n", FW_VERSION_FILE, file_size);
        fclose(file);
        return -1;
    }

    read_size = fread(firmware_name, 1, file_size, file);
    D_DBG("read_size = %d\n", read_size);
    if(file_size != read_size)
    {
        WD_ERR("file_size = %d, read_size = %d, read file failed!\n", file_size, read_size);
        fclose(file);
        return -1;
    }

    char *load_firmware_name = NULL;
    load_firmware_name = strstr(firmware_name, CCM4201S_FW_V);
    if(NULL != load_firmware_name)
    {
        char *bin = NULL;
        bin = strstr(load_firmware_name, ".bin");
        if((NULL != bin) && (bin > load_firmware_name) && (FW_FILE_NAME_LEN_MAX >= (bin-load_firmware_name+4)))
        {
            char fw_file_name[FW_FILE_NAME_LEN_MAX] = {0};
            char str_fmt[FW_FILE_NAME_LEN_MAX+FW_VERSION_LEN_MAX];
            
            memset(str_fmt, 0x00, FW_FILE_NAME_LEN_MAX+FW_VERSION_LEN_MAX);
            strcpy(str_fmt, CCM4201S_FW_V);
            strcat(str_fmt, "%d");
            strcat(str_fmt, FW_FILE_TAIL);

            memcpy(fw_file_name, load_firmware_name, bin-load_firmware_name+4);
            //sscanf(fw_file_name, "CCM4201S_FW_V%d.bin", &(this->ccm4201s_fw.fw_version_num));
            sscanf(fw_file_name, str_fmt, &(this->ccm4201s_fw.fw_version_num));

            WD_DBG("fw_file_name: %s, fw_version_num = %d\n", fw_file_name, this->ccm4201s_fw.fw_version_num);
            if(0 < this->ccm4201s_fw.fw_version_num)
            {
                snprintf(this->ccm4201s_fw.fw_version, FW_VERSION_LEN_MAX, "AFP058_FW_%06d", this->ccm4201s_fw.fw_version_num);
                WD_DBG("firmware version: %s\n", this->ccm4201s_fw.fw_version);
            }
            snprintf(this->ccm4201s_fw.file_path, FILE_PATH_LEN_MAX, "%s%s", CONF_FILE_PATH, fw_file_name);
            WD_DBG("file_path: %s\n", this->ccm4201s_fw.file_path);
        }       
    }

    load_firmware_name = strstr(firmware_name, THM36FP_V);
    if(NULL != load_firmware_name)
    {
        char *bin = NULL;
        bin = strstr(load_firmware_name, ".bin");
        if((NULL != bin) && (bin > load_firmware_name) && (FW_FILE_NAME_LEN_MAX >= (bin-load_firmware_name+4)))
        {
            char fw_file_name[FW_FILE_NAME_LEN_MAX] = {0};
            char str_fmt[FW_FILE_NAME_LEN_MAX+FW_VERSION_LEN_MAX];
            
            memset(str_fmt, 0x00, FW_FILE_NAME_LEN_MAX+FW_VERSION_LEN_MAX);
            strcpy(str_fmt, THM36FP_V);
            strcat(str_fmt, "%d");
            strcat(str_fmt, FW_FILE_TAIL);

            memcpy(fw_file_name, load_firmware_name, bin-load_firmware_name+4);
            //sscanf(fw_file_name, "THM36FP_V%d.bin", &(this->thm36_fw.fw_version_num));
            sscanf(fw_file_name, str_fmt, &(this->thm36_fw.fw_version_num));

            WD_DBG("fw_file_name: %s, fw_version_num = %d\n", fw_file_name, this->thm36_fw.fw_version_num);
            if(0 < this->thm36_fw.fw_version_num)
            {
                snprintf(this->thm36_fw.fw_version, FW_VERSION_LEN_MAX, "thm36_bzy_FWversion%06d", this->thm36_fw.fw_version_num);
            }
            snprintf(this->thm36_fw.file_path, FILE_PATH_LEN_MAX, "%s%s", CONF_FILE_PATH, fw_file_name);
            WD_DBG("file_path: %s\n", this->thm36_fw.file_path);
        }
    }

    load_firmware_name = strstr(firmware_name, ACM32FP_V);
    if(NULL != load_firmware_name)
    {
        char *bin = NULL;
        bin = strstr(load_firmware_name, ".bin");
        if((NULL != bin) && (bin > load_firmware_name) && (FW_FILE_NAME_LEN_MAX >= (bin-load_firmware_name+4)))
        {
            char fw_file_name[FW_FILE_NAME_LEN_MAX] = {0};
            char str_fmt[FW_FILE_NAME_LEN_MAX+FW_VERSION_LEN_MAX];
            
            memset(str_fmt, 0x00, FW_FILE_NAME_LEN_MAX+FW_VERSION_LEN_MAX);
            strcpy(str_fmt, ACM32FP_V);
            strcat(str_fmt, "%d");
            strcat(str_fmt, FW_FILE_TAIL);
        
            memcpy(fw_file_name, load_firmware_name, bin-load_firmware_name+4);
            //sscanf(fw_file_name, "ACM32FP_V%d.bin", &(this->acm32_fw.fw_version_num));
            sscanf(fw_file_name, str_fmt, &(this->acm32_fw.fw_version_num));

            WD_DBG("fw_file_name: %s, fw_version_num = %d\n", fw_file_name, this->acm32_fw.fw_version_num);
            if(0 < this->acm32_fw.fw_version_num)
            {
                snprintf(this->acm32_fw.fw_version, FW_VERSION_LEN_MAX, "acm32_btl_ofilm_pc_%06d", this->acm32_fw.fw_version_num);
            }
            snprintf(this->acm32_fw.file_path, FILE_PATH_LEN_MAX, "%s%s", CONF_FILE_PATH, fw_file_name);
            WD_DBG("file_path: %s\n", this->acm32_fw.file_path);
        }
    }

    return 0;
}


char *upgrade_new_firmware_version(uint8 mcu_type)
{
    UPGRADE_PARAM *this = &upgrade_param;
    char *version = NULL;

    switch(mcu_type)
    {
        case DEVICE_THM36: version = this->thm36_fw.fw_version; break;
        case DEVICE_CCM4201S: version = this->ccm4201s_fw.fw_version; break;
        case DEVICE_ACM32: version = this->acm32_fw.fw_version; break;
        default: version = NULL;break;
    }

    return version;
}

char *upgrade_new_firmware_name(uint8 mcu_type)
{
    UPGRADE_PARAM *this = &upgrade_param;
    char *file_path = NULL;

    switch(mcu_type)
    {
        case DEVICE_THM36: file_path = this->thm36_fw.file_path; break;
        case DEVICE_CCM4201S: file_path = this->ccm4201s_fw.file_path; break;
        case DEVICE_ACM32: file_path = this->acm32_fw.file_path; break;
        default: file_path = NULL;break;
    }

    return file_path;   
}


int32 upgrade_and_run(void)
{
    UPGRADE_PARAM *this = &upgrade_param;
    THM36_UPGRADE_PARAM *thm36 = NULL;
    ACM32_UPGRADE_PARAM *acm32 = NULL;
    CCM4201S_UPGRADE_PARAM *ccm4201s = NULL;
    int upgrade_ret = -1;
    int ret = -1;

    if(NULL == this)
    {
        WD_ERR("the param is ERROR!\n");
        return DRV_ERR;
    }
    thm36 = &(this->thm36);
    acm32 = &(this->acm32);
    ccm4201s = &(this->ccm4201s);
    
    if(DEVICE_THM36 == upgrade_get_boot_mcu_type())
    {
        upgrade_ret = thm36_upgrade_and_run(thm36, this->thm36_fw.file_path);
        if(0 == upgrade_ret)
        {
            WD_LOG("UPGRADE: PASS.\n");
            //usleep(1000 * 1000);
            ret = 0;
            goto END;
        }
        else if(-2 == upgrade_ret)
        {
            ret = -2;
            goto END;
        }
    }
    else if(DEVICE_CCM4201S == upgrade_get_boot_mcu_type())
    {
        upgrade_ret = ccm4201s_upgrade_and_run(ccm4201s, this->ccm4201s_fw.file_path);
        if(0 == upgrade_ret)
        {
            WD_LOG("UPGRADE: PASS.\n");
            //usleep(1000 * 1000);
            ret = 0;
            goto END;
        }
        else if(-2 == upgrade_ret)
        {
            return -2;
            goto END;
        }               
    }
    else if(DEVICE_ACM32 == upgrade_get_boot_mcu_type())
    {
        upgrade_ret = acm32_upgrade_and_run(acm32, this->acm32_fw.file_path);
        if(0 == upgrade_ret)
        {
            WD_LOG("UPGRADE: PASS.\n");
            //usleep(1000 * 1000);
            ret = 0;
            goto END;
        }
        else if(-2 == upgrade_ret)
        {
            return -2;
            goto END;
        }               
    }
END:
    return ret;
}

int32 set_upgrade_state(uint8 state)
{
    WD_LOG("state %d\n", state);
    UPGRADE_PARAM *this = &upgrade_param;
    this->upgrade_state = state;
    return 0;
}

uint8 get_upgrade_state(void)
{
    UPGRADE_PARAM *this = &upgrade_param;
    return this->upgrade_state;
}


int32 upgrade_module_init(void)
{
    UPGRADE_PARAM *this = &upgrade_param;

    memset((uint8 *)&upgrade_param, 0x00, sizeof(UPGRADE_PARAM));
    acm32_upgrade_module_init(&(this->acm32));
    thm36_upgrade_module_init(&(this->thm36));
    ccm4201s_upgrade_module_init(&(this->ccm4201s));

    return DRV_OK;
}


